package com.ruibo.modules.system.service.impl;

import cn.hutool.core.util.ObjectUtil;
import com.ruibo.constants.UserConstants;
import com.ruibo.utils.PageUtil;
import com.ruibo.utils.QueryHelp;
import com.ruibo.utils.StringUtils;
import com.ruibo.utils.UpdateUtil;
import com.ruibo.modules.system.domain.SysDept;
import com.ruibo.modules.system.domain.SysMenu;
import com.ruibo.modules.system.domain.SysRole;
import com.ruibo.modules.system.repository.SysDeptRepository;
import com.ruibo.modules.system.repository.SysMenuRepository;
import com.ruibo.modules.system.repository.SysRoleRepository;
import com.ruibo.modules.system.criteria.RoleQueryCriteria;
import com.ruibo.modules.system.service.dto.RoleSmallDto;
import com.ruibo.modules.system.service.dto.SysRoleDto;
import com.ruibo.modules.system.service.dto.SysUserDto;
import com.ruibo.modules.system.service.mapper.RoleSmallMapper;
import com.ruibo.modules.system.service.mapper.SysRoleMapper;
import com.ruibo.modules.system.service.SysRoleService;
import org.springframework.data.domain.Pageable;
import org.springframework.data.jpa.domain.Specification;
import org.springframework.security.core.GrantedAuthority;
import org.springframework.security.core.authority.SimpleGrantedAuthority;
import org.springframework.stereotype.Service;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.PageRequest;

import javax.annotation.Resource;
import java.util.*;
import java.util.stream.Collectors;

import org.springframework.transaction.annotation.Transactional;

/**
 * (SysRole)表服务实现类
 *
 * @author sunfeng
 * @since 2020-04-17 13:34:58
 */
@Service("sysRoleService")
public class SysRoleServiceImpl implements SysRoleService {
    @Resource
    private SysRoleRepository sysRoleRepository;

    @Resource
    private SysRoleMapper sysRoleMapper;

    @Resource
    private SysDeptRepository sysDeptRepository;

    @Resource
    private SysMenuRepository sysMenuRepository;

    @Resource
    private RoleSmallMapper roleSmallMapper;

    @Override
    public SysRoleDto queryById(Long roleId) {

        SysRole sysRole = sysRoleRepository.findById(roleId).get();
        SysRoleDto sysRoleDto = this.sysRoleMapper.toDto(sysRole);
        List<Long> deptIdList = sysRole.getSysMenus()
                .stream()
                .map(SysMenu::getId)
                .collect(Collectors.toList());
        Long[] deptIds = deptIdList.toArray(new Long[deptIdList.size()]);

        List<Long> menuIdList = sysRole.getSysDepts()
                .stream()
                .map(SysDept::getId)
                .collect(Collectors.toList());
        Long[] menuIds = menuIdList.toArray(new Long[menuIdList.size()]);


        sysRoleDto.setDeptIds(deptIds);
        sysRoleDto.setMenuIds(menuIds);

        return sysRoleDto;
    }

    @Override
    public List<SysRoleDto> findAll() {

        return this.sysRoleMapper.toDto(this.sysRoleRepository.findAll());

    }

    /**
     * 根据用户id用户角色
     *
     * @param userId
     * @return
     */
    @Override
    public List<RoleSmallDto> findByUserId(Long userId) {
        return roleSmallMapper.toDto(new ArrayList<>(sysRoleRepository.findBySysUsers_Id(userId)));
    }

    @Override
    public Set<String> selectRolePermissionByUserId(Long userId) {
        Set<SysRole> sysRoles = sysRoleRepository.findByDelFlagAndSysUsers_Id("0", userId);
        return sysRoles.stream()
                .map(SysRole::getRoleKey).collect(
                        Collectors.toSet());

    }

    @Override
    public Collection<GrantedAuthority> mapToGrantedAuthorities(SysUserDto user) {
        Set<SysRole> roles = sysRoleRepository.findBySysUsers_Id(user.getId());
        Set<String> permissions = roles.stream().filter(SysRole -> StringUtils.isNotBlank(SysRole.getRoleKey())).map(SysRole::getRoleKey).collect(Collectors.toSet());
        permissions.addAll(
                roles.stream().flatMap(role -> role.getSysMenus().stream())
                        .filter(menu -> StringUtils.isNotBlank(menu.getPerms()))
                        .map(SysMenu::getPerms).collect(Collectors.toSet())
        );
        return permissions.stream().map(SimpleGrantedAuthority::new)
                .collect(Collectors.toList());
    }

    @Override
    public List<RoleSmallDto> findByUsersId(Long id) {
        return roleSmallMapper.toDto(new ArrayList<>(sysRoleRepository.findBySysUsers_Id(id)));
    }

    @Override
    public List<Long> selectRoleListByUserId(Long userId) {
        List<Long> collect = sysRoleRepository.findBySysUsers_Id(userId).stream().map(SysRole::getId).collect(Collectors.toList());
        return collect;
    }

    @Override
    public Object queryAll(RoleQueryCriteria criteria, Pageable pageable) {
        Page<SysRole> page = sysRoleRepository.findAll((Specification<SysRole>) (root, criteriaQuery, criteriaBuilder) -> QueryHelp.getPredicate(root, criteria, criteriaBuilder), pageable);
        return PageUtil.toPage(page.map(sysRoleMapper::toDto));
    }

    @Override
    @Transactional
    public int updateRoleStatus(SysRoleDto role) {
        assert role.getId() != null;
        SysRole sysRole = sysRoleRepository.findById(role.getId()).get();
        sysRole.setStatus(role.getStatus());
        sysRoleRepository.save(sysRole);
        return 0;
    }

    /**
     * 验证roleKey 是否唯一
     *
     * @param role 角色信息
     * @return
     */
    @Override
    public String checkRoleKeyUnique(SysRoleDto role) {
        Long roleId = StringUtils.isNull(role.getId()) ? -1L : role.getId();

        SysRole info = sysRoleRepository.findByRoleKey(role.getRoleKey());

        if (StringUtils.isNotNull(info) && info.getId().longValue() != roleId.longValue()) {
            return UserConstants.NOT_UNIQUE;
        }
        return UserConstants.UNIQUE;
    }

    /**
     * 验证角色是否唯一
     *
     * @param role 角色信息
     * @return
     */
    @Override
    public String checkRoleNameUnique(SysRoleDto role) {

        Long roleId = StringUtils.isNull(role.getId()) ? -1L : role.getId();

        SysRole info = sysRoleRepository.findByRoleName(role.getRoleName());
        if (StringUtils.isNotNull(info) && info.getId().longValue() != roleId.longValue()) {
            return UserConstants.NOT_UNIQUE;
        }
        return UserConstants.UNIQUE;
    }

    /**
     * 校验是否有权限
     *
     * @param role 角色信息
     */
    @Override
    public void checkRoleAllowed(SysRoleDto role) {
        if (StringUtils.isNotNull(role.getId()) && role.isAdmin()) {
            throw new RuntimeException("不允许操作超级管理员角色");
        }
    }


    @Override
    public Object queryAllByLimit(int offset, int limit) {

        return PageUtil.toPage(this.sysRoleRepository.findAll(PageRequest.of((offset - 1)
                * limit, limit)).map(sysRoleMapper::toDto));

    }

    @Override
    @Transactional
    public SysRoleDto insert(SysRoleDto sysRoleDto) {

        // 处理 sysRole

        SysRole sysRole = new SysRole();
        UpdateUtil.copyNullProperties(sysRoleDto, sysRole);

        // 获取关联的菜单
        List<SysMenu> sysMenuList = sysMenuRepository.
                findAllById(Arrays.asList(sysRoleDto.getMenuIds()));
        HashSet<SysMenu> sysMenus = new HashSet<>(sysMenuList);
        sysRole.setSysMenus(sysMenus);
        // 获取关联的部门
        List<SysDept> sysDeptList = sysDeptRepository.
                findAllById(Arrays.asList(sysRoleDto.getDeptIds()));
        HashSet<SysDept> sysDepts = new HashSet<>(sysDeptList);
        sysRole.setSysDepts(sysDepts);
        SysRole save = sysRoleRepository.save(sysRole);

        return this.sysRoleMapper.toDto(save);

    }


    @Override
    @Transactional
    public SysRoleDto update(SysRoleDto sysRoleDto) {
        // 处理 sysRole

        SysRole sysRole = sysRoleRepository.findById(sysRoleDto.getId()).get();
        UpdateUtil.copyNullProperties(sysRoleDto, sysRole);

        // 获取关联的菜单
        if (ObjectUtil.isNotEmpty(sysRoleDto.getMenuIds())) {
            List<SysMenu> sysMenuList = sysMenuRepository.
                    findAllById(Arrays.asList(sysRoleDto.getMenuIds()));
            HashSet<SysMenu> sysMenus = new HashSet<>(sysMenuList);
            sysRole.setSysMenus(sysMenus);
            // 删除关联的菜单
        } else {
            sysRole.setSysMenus(null);
        }
        // 获取关联的部门   目前角色不进行关联部门
        if (ObjectUtil.isNotEmpty(sysRoleDto.getDeptIds())) {
            List<SysDept> sysDeptList = sysDeptRepository.
                    findAllById(Arrays.asList(sysRoleDto.getDeptIds()));
            HashSet<SysDept> sysDepts = new HashSet<>(sysDeptList);
            sysRole.setSysDepts(sysDepts);
        } else {
            sysRole.setSysDepts(null);
        }
        SysRole save = sysRoleRepository.save(sysRole);
        return this.sysRoleMapper.toDto(save);
    }

    /**
     * 根据roleId 删除 信息
     *
     * @param roleIds /
     * @return
     */
    @Override
    @Transactional
    public void deleteById(Long[] roleIds) {
        // 清空role的绑定关系  然后删除

        for (Long roleId : roleIds) {
            SysRole sysRole = sysRoleRepository.findById(roleId).get();
            sysRole.setSysDepts(null);
            sysRole.setSysMenus(null);
            sysRoleRepository.save(sysRole);
            sysRoleRepository.deleteById(roleId);
        }
    }
}
